﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FarseerGames.FarseerPhysics.Mathematics;
using FreeGoo.GameEngine.FarSeer;
using FarseerGames.FarseerPhysics;

namespace FreeGoo.GameEngine.Renderables.Particles.States
{
    public class Selected : ParticleState
    {
        public const int MouseSpringMaxAcceleration = 12000;
        public const float ThrustCutoffRadiusMultiplier = 0.35f;
        public const int LinkableDistance = 75;
        public const int BreakpointRadiusMultiplier = 1000;
        public const float StartDragRadiusFaction = 2.0f;

        private float _linearDragCoefficient;
        private float _mass;
        private MouseSpring _mouseSpring;
        private float _startDragAtDistanceSquared;

        public Selected(Particle particle)
            : base(particle)
        {
            _startDragAtDistanceSquared = (float) Math.Pow(Particle.Radius * StartDragRadiusFaction, 2);
        }

        public override CollisionCategory StateCollissionCatagory { get { return Engine.LinkedParticleCollisionCategory; } }
        public override CollisionCategory StateCollidesWith { get { return Engine.StaticCollisionCategory; } }
        public bool DragStarted { get; protected set; }

        public override void PerformStatePhysicsAction()
        {
            float distanceSquared = Vector2.DistanceSquared(Engine.UserInputController.CursorPosition, Particle.Position);
            if (!DragStarted)
            {
                if (distanceSquared >= _startDragAtDistanceSquared)
                {
                    DoStartDrag();
                }
            }
            else
            {
                if (distanceSquared > Particle.RadiusSquared * 4)
                {
                    Particle.Body.LinearDragCoefficient = 0;
                }
                else
                {
                    Particle.Body.LinearDragCoefficient = 400;
                }
            }
        }

        public void DoStartDrag()
        {
            if (!DragStarted)
            {
                DragStarted = true;
                _mouseSpring = new MouseSpring(Particle.Body, Vector2.Zero, Engine.UserInputController.CursorPosition, MouseSpringMaxAcceleration);
                _mouseSpring.ThrustCutoffDistance = Particle.Radius * ThrustCutoffRadiusMultiplier;
                _mouseSpring.Breakpoint = Particle.Radius * BreakpointRadiusMultiplier;
                _mouseSpring.Broke += new EventHandler<EventArgs>(_mouseSpring_Broke);
                Engine.PhysicsSimulator.Add(_mouseSpring);

                _linearDragCoefficient = Particle.Body.LinearDragCoefficient;
                _mass = Particle.Body.Mass;

                Particle.Body.IgnoreGravity = true;
                Particle.Body.LinearDragCoefficient = 75;
                Particle.Body.Mass = Particle.Body.Mass / 10;
                Particle.ClearLinks();
                Particle.SignalStateChanged();
            }
        }

        public override void EnteringState()
        {
            base.EnteringState();

            if (!Particle.IsLinked)
            {
                DoStartDrag();
            }
        }

        public override void ExitingState()
        {
            base.EnteringState();

            if (DragStarted)
            {
                Engine.PhysicsSimulator.Remove(_mouseSpring);
                _mouseSpring.Body = null;
                _mouseSpring.Dispose();

                Particle.Body.IgnoreGravity = false;
                Particle.Body.LinearDragCoefficient = _linearDragCoefficient;
                Particle.Body.Mass = _mass;
            }
        }

        internal void ControllerMovedTo(Vector2 cursorPosition)
        {
            if (DragStarted)
            {
                _mouseSpring.TargetPoint = cursorPosition;
            }
        }

        private void _mouseSpring_Broke(object sender, EventArgs e)
        {
            Engine.UserInputController.Release(true);
        }
    }
}
